﻿using System.Timers;
using System.Threading;
using System.Collections;

using FileWatcher.Action;
using FileWatcher.NodeInfo;

using Blackhole.Debug;

namespace FileWatcher
{
    public class WatchDog
    {
        private Node m_rootNode;
        private IAction m_action;
        private WatchDogTimer m_trigger;
        private Thread m_watchdogThread;
        private FileWatcherSettings m_settings;

        public FileWatcherSettings Settings
        {
            get { return this.m_settings; }
        }

        public IAction Action
        {
            set { this.m_action = value; }
            get { return this.m_action; }
        }

        public WatchDog(FileWatcherSettings settings)
        {
            this.m_settings = settings;

            this.m_rootNode = new Node(new FolderNodeInfo(settings.Root), this.m_settings.Recursive, this.m_settings.Cycle, this.m_settings.AcceptPattern);

            this.m_rootNode.BuildTree(this.m_settings.ProcessExisting);

            this.m_trigger = new WatchDogTimer(new WatchDogTimer.Scan(this.Scan), m_settings.Timeout * 1000);

            this.m_watchdogThread = new Thread(new ThreadStart(this.Run));
        }

        public WatchDog(FileWatcherSettings settings, IAction action)
            : this(settings)
        {
            this.Action = action;
        }

        private void Scan()
        {
            ArrayList readyFiles = new ArrayList();

            this.m_rootNode = this.m_rootNode.GetChanges(readyFiles);

            Garbage.Log(this, new LoggerArguements(LoggerArguements.LoggerLevels.All, "{0} files ready", readyFiles.Count));

            for (int i = 0; i < readyFiles.Count; i++)
            {
                this.m_action.Process(readyFiles[i] as Node);
            }
        }

        public void Start()
        {
            this.m_rootNode = new Node(new FolderNodeInfo(Settings.Root), this.m_settings.Recursive, this.m_settings.Cycle, this.m_settings.AcceptPattern);

            this.m_rootNode.BuildTree(this.m_settings.ProcessExisting);

            this.m_watchdogThread = new Thread(new ThreadStart(this.Run));

            this.m_watchdogThread.Start();
        }

        public void Stop()
        {
            this.m_trigger.Release();
        }

        private void Run()
        {
            this.m_trigger.Trigger();
        }

        public void UpdateSettings(FileWatcherSettings settings)
        {
            this.m_settings = settings;
        }
    }

    public class WatchDogTimer
    {
        public delegate void Scan();

        private Scan m_scanMethod;
        private System.Timers.Timer m_internalTimer;

        public double Interval
        {
            set { this.m_internalTimer.Interval = value; }
        }

        public WatchDogTimer(Scan scanMethod, double interval)
        {
            this.m_scanMethod = scanMethod;

            this.m_internalTimer = new System.Timers.Timer();

            this.m_internalTimer.Interval = interval;

            this.m_internalTimer.Elapsed += new ElapsedEventHandler(internalTimer_Elapsed);
        }

        private void internalTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this.m_internalTimer.Stop();

            this.m_scanMethod();

            this.m_internalTimer.Start();
        }

        public void Trigger()
        {
            this.m_internalTimer.Start();
        }

        public void Release()
        {
            this.m_internalTimer.Stop();
        }
    }
}